跳到主要内容

SpringBoot 配置文件相关

注册为 Bean 的注解

一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,采用以下注解可实现:

  • @Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean不知道属于哪个层,可以使用 @Component 注解标注。
  • @Repository: 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
  • @Controller: 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。

yml 配置文件的编写

注意:yaml 与 properties 配置文件除了展示方式不同,其他的功能都是一样的(读取方式无需改变)

语法特征:

  1. 树状层次结构展示配置项
  2. 配置项之间如果有关系的话需要分行空两格
  3. 配置项如果有值的话,那么需要在 : 之后空一格再写配置项值
jdbc:
driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_test?useUnicode=true&characterEncoding=utf8&useSSL=true&useServerPrepStmts=true
username: root
password: 123

- 开头的行表示构成一个数组:

- A
- B
- C

多个 yml 配置文件

多个 yml 配置文件时,这些配置文件的名称必须为 application-xxx.yml 并且这些配置文件必须要在 application.yml 配置文件中激活之后才可以使用

例如定义了 application-abc.ymlapplication-def.yml 两个文件,则在 application.yml 中激活(加入如下字段)

spring:
profiles:
active: abc,def
# 激活配置文件只需指定 - 后面的名称就好了

properties 文件激活也差不多

# 激活 jdbc yml文件
spring.profiles.active=abc,def

如果 properties 和 yml 配置文件同时存在 Spring Boot 项目中,那么这两类配置文件都有效(同名的话会以 properties 文件为主)

配置多套环境

在 Spring Boot 中多环境配置文件名需要满足 application-{profile}.properties 的格式,其中 {profile} 对应你的环境标识(不一定是 .properties 文件,也可以是 .yml 文件).profile 的值,是开发者自定义的,只需要在启动的时候,添加对应的参数,SpringBoot 就会去读取该配置文件了。比如我们可以定义为如下格式:

application-dev.properties:开发环境 
application-test.properties:测试环境
application-prod.properties:生产环境

如果启动的时候,没有指定配置文件,或者指定的配置文件没有对应的项,则会从默认的配置文件中读取。

我们可以通过 spring.profiles.active 参数来指定环境。

启动指定环境的方法

1、命令行启动指定 可以添加 -Dspring.profiles.active=<profile> 的方式指定

如,指定 happy 环境:

java -jar "-Dspring.profiles.active=happy" springboot-0.0.1-SNAPSHOT.jar

2、在 IDEA 中指定 在 run/debug configuration 中,可以配置环境,如下:

配置用到的注解

在 Spring 的时候就提到过配置 Bean 有两种方式,一个是通过 XML 文件,一个是注解,现在到了 SpringBoot 则是完全采用注解的形式进行配置

回顾一下配置用的注解

  • @Configuration:声明一个类作为配置类
  • @Bean:声明在方法上,将方法的返回值加入 Bean 容器,代替 <Bean> 标签
  • @Value:属性注入
  • @PropertySource:指定外部属性文件(properties 文件)
  • @ConfigurationProperties 直接读取配置项

在配置类里面读取配置文件

如下,编写一个 JDBC 的配置类

注:一般不使用 @Value 注解,直接使用 @ConfigurationProperties 注解就能读取全部配置项(下面有演示),这里是为了演示

@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {

@Value("${jdbc.url}")
String url;

@Value("${jdbc.driver}")
String driverClassName;

@Value("${jdbc.username}")
String username;

@Value("${jdbc.password}")
String password;

@Bean
public DataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setUrl(url);
druidDataSource.setPassword(password);
druidDataSource.setUsername(username);
return druidDataSource;
}
}

指定读取哪个文件

@PropertySource 读取指定 properties 文件

@Component
@PropertySource("classpath:website.properties")
@Getter
@Setter
class WebSite {
@Value("${url}")
private String url;
}

使用例:

@Autowired
private WebSite webSite;

System.out.println(webSite.getUrl());

直接读取数据与 Bean 绑定

LibraryProperties 类上加了 @Component 注解,我们可以像使用普通 Bean 一样将其注入到类中使用,这里直接使用 @ConfigurationProperties 注解就能读取全部配置项

@Component
@ConfigurationProperties(prefix = "library")
@Setter
@Getter
@ToString
class LibraryProperties {
private String location;
private List<Book> books;

@Setter
@Getter
@ToString
static class Book {
String name;
String description;
}
}

这个时候你就可以像使用普通 bean 一样,将其注入到类中使用:

@SpringBootApplication
public class ReadConfigPropertiesApplication implements InitializingBean {

private final LibraryProperties library;

public ReadConfigPropertiesApplication(LibraryProperties library) {
this.library = library;
}

public static void main(String[] args) {
SpringApplication.run(ReadConfigPropertiesApplication.class, args);
}

@Override
public void afterPropertiesSet() {
System.out.println(library.getLocation());
System.out.println(library.getBooks()); }
}

通过 @ConfigurationProperties 读取并校验

application.yml 修改为如下内容,明显看出这不是一个正确的 email 格式:

my-profile:
name: temp
email: temp@

ProfileProperties 类没有加 @Component 注解。在我们要使用 ProfileProperties 的地方使用 @EnableConfigurationProperties 注册我们的配置 Bean:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated; // 注意这个包

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;


@Getter
@Setter
@ToString
@ConfigurationProperties("my-profile")
@Validated
public class ProfileProperties {
@NotEmpty
private String name;

@Email // 使用了上面 validation 包内的工具
@NotEmpty
private String email;

//配置文件中没有读取到的话就用默认值
private Boolean handsome = Boolean.TRUE;

}

具体使用:

@SpringBootApplication
@EnableConfigurationProperties(ProfileProperties.class)
public class ReadConfigPropertiesApplication implements InitializingBean {
private final ProfileProperties profileProperties;

public ReadConfigPropertiesApplication(ProfileProperties profileProperties) {
this.profileProperties = profileProperties;
}

public static void main(String[] args) {
SpringApplication.run(ReadConfigPropertiesApplication.class, args);
}

@Override
public void afterPropertiesSet() {
System.out.println(profileProperties.toString());
}
}

编写装载配置类演示:RSA 案例

先导入配置依赖:

为了方便书写配置文件,SpringBoot 会提示你添加一个依赖(配置文件处理器)

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

这里使用 RSA 配置的那篇笔记的粒子

在 yml 文件添加如下自定义的配置

rsa:
key:
pubKeyPath: "classpath:rsa/id_key_rsa.pub"
priKeyPath: "classpath:rsa/id_key_rsa"

创建一个自定义类

@Data
@ConfigurationProperties("rsa.key") //指定配置文件的key
public class RsaKeyProperties {
@Autowired
private ResourceLoader resourceLoader;

private String pubKeyPath;
private String priKeyPath;

private PublicKey publicKey;
private PrivateKey privateKey;

@PostConstruct
public void createKey() throws Exception {
// 先取得路径,因为使用的是 classpath 的形式,所以得使用 Spring 提供的路径工具
String pp = resourceLoader.getResource(pubKeyPath).getFile().getAbsolutePath();
String pk = resourceLoader.getResource(priKeyPath).getFile().getAbsolutePath();

this.publicKey = RsaUtils.getPublicKey(pp);
this.privateKey = RsaUtils.getPrivateKey(pk);
}
}

然后再在启动类里面注册这个配置类

@SpringBootApplication
@EnableConfigurationProperties(RsaKeyProperties.class) // 将配置类放入 Spring 容器中
public class OAuthApplication {
public static void main(String[] args) {
SpringApplication.run(OAuthApplication.class, args);
}
}

这时就已经可以读取到参数了,但是可以发现 IDEA 这里还是有警告,而且如何设置这个自定义参数的说明呢?

只需要加上 @NestedConfigurationProperty 注解即可

@NestedConfigurationProperty
private String pubKeyPath;
@NestedConfigurationProperty
private String priKeyPath;

在对应配置文件 ait+回车 自动生成下面这个文件,填上注释就行了

{
"properties": [
{
"name": "rsa.key.priKeyPath",
"type": "java.lang.String",
"description": "自定义的私钥位置."
},
{
"name": "rsa.key.pubKeyPath",
"type": "java.lang.String",
"description": "自定义的公钥位置."
}
]
}

然后输入命令

mvn clean package

注意,如果显示依赖问题(微服务情况下)则把各个子模块都 install 一下(就是将它们添加到本地依赖中)

然后就能显示说明了

Docker 动态传参

假设现在有一个 Springboot 项目,它里面有一个数据库的配置项,但是不同的数据库测试环境 (DEV\SIT\UAT),数据库 ip有多个,想使用同一个 Springboot 项目镜像,可以随时切换数据库配置,简单来说就是你的 Springboot 应用的数据库配置应该是通过外部传入,而不是 hardcode

Springboot 应用里有个数据库配置如下:

spring.datasource.url = jdbc:mysql://192.168.0.11:3306/db?useUnicode=true&characterEncoding=utf8
#配置数据库用户名
spring.datasource.username = sa
#配置数据库密码
spring.datasource.password = sa

解决方案

利用 SpEL 表达式,动态从环境变量获取数据库配置

接下来我们在 Springboot 配置文件把数据库配置用 spEL 表达式替换

#配置数据库链接
spring.datasource.url = jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?useUnicode=true&characterEncoding=utf8
#配置数据库用户名
spring.datasource.username = ${DB_USER}
#配置数据库密码
spring.datasource.password = ${DB_PASSWORD}

docker-compose.yml 配置我们的数据库参数

version: '3'
services:
web:
restart: always
depends_on:
- db
image: springboot-app-image
build: .
ports:
- 8080:8080
environment:
- DB_HOST=192.168.0.11
- DB_PORT=3306
- DB_USER=root
- DB_PASSWORD=123456
- DB_NAME=db
networks:
- credit-facility-net
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s

Reference

Docker如何给Springboot项目动态传参